
package com.google.code.lebar.bean.request;


import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.code.lebar.bean.request.oauth.OAuthData;


public class LayarRequest
{
    private static final Logger logger = Logger.getLogger( LayarRequest.class.getName() );

    // private String userId;
    // private String layerName;
    // private String version;
    // private Double lat;
    // private Double lon;
    // private String countryCode;
    // private String lang;
    // private String action;
    // private Integer accuracy;
    // private String pageKey;

    private OAuthData oAuth;
    private List<String> checkBoxList;
    private List<String> searchBoxTerms;

    // private String selectedRadioListValue;
    // private Integer radius;
    //
    // private String localCountryCode;
    // private Integer alt;
    // private String recognizedReferenceImage;

    private Map<Object, Object> mRequestMap = null;

    /**
     * @return the accuracy
     */
    public Integer getAccuracy()
    {
        return getFieldValueAs( LayarRequestField.ACCURACY, Integer.class );
    }

    /**
     * @return the action
     */
    public String getAction()
    {
        return getFieldValueAs( LayarRequestField.ACTION, String.class );
    }

    /**
     * @return the alt
     */
    public Integer getAlt()
    {
        return getFieldValueAs( LayarRequestField.ALT, Integer.class );
    }

    /**
     * @return the checkBoxList
     */
    public List<String> getCheckBoxList()
    {
        // FIXME
        return null;
    }

    /**
     * @return the countryCode
     */
    public String getCountryCode()
    {
        return getFieldValueAs( LayarRequestField.COUNTRY_CODE, String.class );
    }

    @SuppressWarnings( "unchecked" )
    private <T> T getFieldValueAs( LayarRequestField pField, Class<T> pValueClass )
    {
        Object tFieldValue = getRequestMap().get( pField.getFieldString() );

        if ( tFieldValue == null ) return null;

//        System.out.println( "requested class = " + pValueClass.getName() );
//        System.out.println( "actual class = " + tFieldValue.getClass().getName() );
//        System.out.println( "pValueClass.isAssignableFrom( tFieldValue.getClass() ) = " + pValueClass.isAssignableFrom( tFieldValue.getClass() ) );
//        System.out.println( "tFieldValue.getClass().isArray() = " + tFieldValue.getClass().isArray() );

        // Field value is not null, ensure that the value is of the expected
        // class
        if ( pValueClass.isAssignableFrom( tFieldValue.getClass() ) )
        {
            return (T) tFieldValue;
        }

        // If the value is an array, unpack the array, store the first value,
        // and then re-fetch the data
        if ( tFieldValue.getClass().isArray() )
        {
            Object[] tFieldValues = (Object[]) tFieldValue;
            putValueForMapField( pField, tFieldValues[0] );
            return getFieldValueAs( pField, pValueClass );
        }

        // If the field value is a String, and the requested class is either a
        // Integer or Double, we perform proper numerical parsing and store the
        // result in the map so that we would not need to reparse the value.
        if ( tFieldValue instanceof String )
        {
            String tFieldStringValue = (String) tFieldValue;

            if ( Integer.class.isAssignableFrom( pValueClass ) )
            {
                Integer tFieldIntegerValue = parseValueAsInteger( tFieldStringValue );
                putValueForMapField( pField, tFieldIntegerValue );
                return (T) tFieldIntegerValue;
            }
            else if ( Double.class.isAssignableFrom( pValueClass ) )
            {
                Double tFieldDoubleValue = parseValueAsDouble( tFieldStringValue );
                putValueForMapField( pField, tFieldDoubleValue );
                return (T) tFieldDoubleValue;
            }
        }

        return null;
    }

    /**
     * @return the lang
     */
    public String getLang()
    {
        return getFieldValueAs( LayarRequestField.LANG, String.class );
    }

    /**
     * @return the lat
     */
    public Double getLat()
    {
        return getFieldValueAs( LayarRequestField.LAT, Double.class );
    }

    /**
     * @return the layerName
     */
    public String getLayerName()
    {
        return getFieldValueAs( LayarRequestField.LAYER_NAME, String.class );
    }

    /**
     * @return the localCountryCode
     */
    public String getLocalCountryCode()
    {
        return getFieldValueAs( LayarRequestField.LOCAL_COUNTRY_CODE, String.class );
    }

    /**
     * @return the lon
     */
    public Double getLon()
    {
        return getFieldValueAs( LayarRequestField.LON, Double.class );
    }

    /**
     * @return the oAuth
     */
    public OAuthData getOAuth()
    {
        // FIXME
        return null;
    }

    /**
     * @return the pageKey
     */
    public String getPageKey()
    {
        return getFieldValueAs( LayarRequestField.PAGE_KEY, String.class );
    }

    /**
     * @return the radius
     */
    public Integer getRadius()
    {
        return getFieldValueAs( LayarRequestField.RADIUS, Integer.class );
    }

    /**
     * @return the recognizedReferenceImage
     */
    public String getRecognizedReferenceImage()
    {
        return getFieldValueAs( LayarRequestField.RECOGNIZED_REFERENCE_IMAGE, String.class );
    }

    Map<Object, Object> getRequestMap()
    {
        if ( mRequestMap == null )
        {
            mRequestMap = new HashMap<Object, Object>();
        }
        return mRequestMap;
    }

    /**
     * @return the searchBoxTerms
     */
    public List<String> getSearchBoxTerms()
    {
        // FIXME
        return null;
    }

    /**
     * @return the selectedRadioListValue
     */
    public String getSelectedRadioListValue()
    {
        return getFieldValueAs( LayarRequestField.RADIO_LIST, String.class );
    }

    /**
     * @return the userId
     */
    public String getUserId()
    {
        return getFieldValueAs( LayarRequestField.USER_ID, String.class );
    }

    /**
     * @return the version
     */
    public String getVersion()
    {
        return getFieldValueAs( LayarRequestField.VERSION, String.class );
    }

    public void importValuesFromMap( Map<Object, Object> pMap )
    {
        getRequestMap().putAll( pMap );
    }

    private Double parseValueAsDouble( String pStringValue )
    {
        try
        {
            return Double.parseDouble( pStringValue );
        }
        catch ( NumberFormatException ex )
        {
            logger.log( Level.FINER, "Cannot parse value " + pStringValue + " as double." );
        }
        return null;
    }

    private Integer parseValueAsInteger( String pStringValue )
    {
        try
        {
            return Integer.parseInt( pStringValue );
        }
        catch ( NumberFormatException ex )
        {
            logger.log( Level.FINER, "Cannot parse value " + pStringValue + " as integer." );
        }
        return null;
    }

    private void putValueForMapField( LayarRequestField pField, Object pValue )
    {
        getRequestMap().put( pField.getFieldString(), pValue );
    }

    /**
     * @param accuracy
     *            the accuracy to set
     */
    public void setAccuracy( Integer accuracy )
    {
        putValueForMapField( LayarRequestField.ACCURACY, accuracy );
    }

    /**
     * @param action
     *            the action to set
     */
    public void setAction( String action )
    {
        putValueForMapField( LayarRequestField.ACTION, action );
    }

    /**
     * @param alt
     *            the alt to set
     */
    public void setAlt( Integer alt )
    {
        putValueForMapField( LayarRequestField.ALT, alt );
    }

    /**
     * @param checkBoxList
     *            the checkBoxList to set
     */
    public void setCheckBoxList( List<String> checkBoxList )
    {
        // FIXME
    }

    /**
     * @param countryCode
     *            the countryCode to set
     */
    public void setCountryCode( String countryCode )
    {
        putValueForMapField( LayarRequestField.COUNTRY_CODE, countryCode );
    }

    /**
     * @param lang
     *            the lang to set
     */
    public void setLang( String lang )
    {
        putValueForMapField( LayarRequestField.LANG, lang );
    }

    /**
     * @param lat
     *            the lat to set
     */
    public void setLat( Double lat )
    {
        putValueForMapField( LayarRequestField.LAT, lat );
    }

    /**
     * @param layerName
     *            the layerName to set
     */
    public void setLayerName( String layerName )
    {
        putValueForMapField( LayarRequestField.LAYER_NAME, layerName );
    }

    /**
     * @param localCountryCode
     *            the localCountryCode to set
     */
    public void setLocalCountryCode( String localCountryCode )
    {
        putValueForMapField( LayarRequestField.LOCAL_COUNTRY_CODE, localCountryCode );
    }

    /**
     * @param lon
     *            the lon to set
     */
    public void setLon( Double lon )
    {
        putValueForMapField( LayarRequestField.LON, lon );
    }

    /**
     * @param oAuth
     *            the oAuth to set
     */
    public void setOAuth( OAuthData oAuth )
    {
        // FIXME
    }

    /**
     * @param pageKey
     *            the pageKey to set
     */
    public void setPageKey( String pageKey )
    {
        putValueForMapField( LayarRequestField.PAGE_KEY, pageKey );
    }

    /**
     * @param radius
     *            the radius to set
     */
    public void setRadius( Integer radius )
    {
        putValueForMapField( LayarRequestField.RADIUS, radius );
    }

    /**
     * @param recognizedReferenceImage
     *            the recognizedReferenceImage to set
     */
    public void setRecognizedReferenceImage( String recognizedReferenceImage )
    {
        putValueForMapField( LayarRequestField.RECOGNIZED_REFERENCE_IMAGE, recognizedReferenceImage );
    }

    /**
     * @param searchBoxTerms
     *            the searchBoxTerms to set
     */
    public void setSearchBoxTerms( List<String> searchBoxTerms )
    {
        // FIXME
    }

    /**
     * @param selectedRadioListValue
     *            the selectedRadioListValue to set
     */
    public void setSelectedRadioListValue( String selectedRadioListValue )
    {
        putValueForMapField( LayarRequestField.RADIO_LIST, selectedRadioListValue );
    }

    /**
     * @param userId
     *            the userId to set
     */
    public void setUserId( String userId )
    {
        putValueForMapField( LayarRequestField.USER_ID, userId );
    }

    /**
     * @param version
     *            the version to set
     */
    public void setVersion( String version )
    {
        putValueForMapField( LayarRequestField.VERSION, version );
    }
}
